<?php
defined('_JEXEC') or die('Restricted access');

/**
 * Description of DatabaseAdapter
 * 
 * @todo 
 * 
 * @author George Zeakis<zeageorge@google.com>
 * 
 */
class DatabaseAdapter implements DatabaseAdapterInterface{
    
    /**
     * @var PDO
     */
    protected $_pdo = NULL;

    /**
     *
     * @var array
     */
    protected $_vars = NULL;

    /**
     * @return DatabaseAdapterInterface
     */
    public function __construct() {
        $this->_vars = array('dbData'=>'');
    }
    
    /**
     * 
     * @todo 
     * 
     * @param array $dbData An array of the form, eg.:
     *                      array(
     *                         'DB_TYPE'=>'some type',
     *                         'DB_HOST'=>'localhost',
     *                         'DB_NAME'=>'db_name',
     *                         'DB_USER'=>'username',
     *                         'DB_PASS'=>'password',
     *                         'TABLE_PREFIX'=> 'tbl_',      
     * @return boolean Returns TRUE on success
     */
    public function connect(array $dbData){
        $tmp = __FUNCTION__."_tmp"; if (isset($this->_vars["$tmp"])){ unset($this->_vars["$tmp"]); }
        try {
            $this->_vars['dbData'] = $dbData;

            if (!is_null($this->_pdo)){ $this->disconnect(); }

            $this->_pdo = new PDO($this->_vars['dbData']['DB_TYPE'] . ':host=' . $this->_vars['dbData']['DB_HOST'] . ';dbname=' . $this->_vars['dbData']['DB_NAME'],
                                  $this->_vars['dbData']['DB_USER'], $this->_vars['dbData']['DB_PASS'], array(PDO::MYSQL_ATTR_INIT_COMMAND => "SET NAMES utf8"));
            
            $this->_pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
            $this->_pdo->exec("SET CHARACTER SET utf8");
        } catch (Exception $exc) {
            // error/Exception handler
        }
        return TRUE; 
        //     or return $this so we can do:
        //     $db = new DatabaseAdapter();
        //     $re = $db->connect($dbData)->select();
    }
    
    /**
     * 
     */
    public function disconnect(){
        $tmp = __FUNCTION__."_tmp"; if (isset($this->_vars["$tmp"])){ unset($this->_vars["$tmp"]); }
        
        $this->_pdo = NULL;
    }

    /**
     * 
     * @return array
     */
    public function get_dbData(){ 
        $tmp = __FUNCTION__."_tmp"; if (isset($this->_vars["$tmp"])){ unset($this->_vars["$tmp"]); }
        
        return $this->_vars['dbData']; 
    }

    /**
     * Quote a string that is used as an identifier
     * (table names, column names etc). This method can
     * also deal with dot-separated identifiers eg table.column
     */
    protected function _quote_identifier($identifier) {
        $tmp = __FUNCTION__."_tmp"; if (isset($this->_vars["$tmp"])){ unset($this->_vars["$tmp"]); }
        
        $parts = explode('.', $identifier);
        $parts = array_map(array($this, '_quote_identifier_part'), $parts);
        return join('.', $parts);
    }

    /**
     * This method performs the actual quoting of a single
     * part of an identifier, using the identifier quote
     * character specified in the config (or autodetected).
     */
    protected function _quote_identifier_part($part) {
        $tmp = __FUNCTION__."_tmp"; if (isset($this->_vars["$tmp"])){ unset($this->_vars["$tmp"]); }
        
        if ($part === '*') {
            return $part;
        }
        $quote_character = '`';
        return $quote_character . $part . $quote_character;
    }

    /**
     * select
     * @param string $sqlQuery An SQL query string
     * @param array $BindParams Paramters to bind
     * @param constant $fetchMode A PDO Fetch mode
     * @return array Returns an assoc array
     */
    public function select($sqlQuery, array $BindParams = array(), $fetchMode = PDO::FETCH_ASSOC){
        $tmp = __FUNCTION__."_tmp"; if (isset($this->_vars["$tmp"])){ unset($this->_vars["$tmp"]); }
        try {
            $this->_vars["$tmp"]["sqlQuery"]   = $sqlQuery;
            $this->_vars["$tmp"]["bindParams"] = $BindParams;
            $this->_vars["$tmp"]["fetchMode"]  = $fetchMode;
        
            $sth = $this->_pdo->prepare($this->_vars["$tmp"]["sqlQuery"]);
            foreach ($this->_vars["$tmp"]["bindParams"] as $key => $value) { $sth->bindValue("$key", $value); }
            
            $this->_vars["$tmp"]["selectResults"]     = $sth->execute();
            $this->_vars["$tmp"]["selectResultsData"] = $sth->fetchAll($this->_vars["$tmp"]["fetchMode"]);
        } catch (Exception $exc) {
            // error/Exception handler
        }
        $re = $this->_vars["$tmp"]["selectResultsData"]; unset($this->_vars["$tmp"]);
        return $re;
    }

    /**
     * insert
     * @param string $table A name of table to insert into
     * @param string $data An associative array
     * @return integer Returns the id of the inserted row
     */
    public function insert($table, array $data) {
        $tmp = __FUNCTION__."_tmp"; if (isset($this->_vars["$tmp"])){ unset($this->_vars["$tmp"]); }
        try{
            $this->_vars["$tmp"]["tableName"] = $table;
            $this->_vars["$tmp"]["dataToInsert"] = $data;

            ksort($this->_vars["$tmp"]["dataToInsert"]);
            $fieldNames = implode('`, `', array_keys($this->_vars["$tmp"]["dataToInsert"]));
            $fieldValues = ':' . implode(', :', array_keys($this->_vars["$tmp"]["dataToInsert"]));

            $this->_vars["$tmp"]["sqlQuery"] = "INSERT INTO `".$this->_vars["$tmp"]["tableName"]."` (`$fieldNames`) VALUES ($fieldValues)";

            $sth = $this->_pdo->prepare($this->_vars["$tmp"]["sqlQuery"]);
            foreach ($this->_vars["$tmp"]["dataToInsert"] as $key => $value) { $sth->bindValue(":$key", $value); }
            
            $this->_vars["$tmp"]["insertResults"] = $sth->execute();
            $this->_vars["$tmp"]["lastInsertID"]  = $this->_pdo->lastInsertId();
        } catch (Exception $exc){
            // error/Exception handler
        }
        $re = $this->_vars["$tmp"]["lastInsertID"]; unset($this->_vars["$tmp"]);
        return $re;
    }

    /**
     * update
     * @param string $table A name of table to insert into
     * @param array $data An associative array
     * @param string $where the WHERE query part
     * @return integer Returns the number of affected rows
     */
    public function update($table, array $data, $where) {
        $tmp = __FUNCTION__."_tmp"; if (isset($this->_vars["$tmp"])){ unset($this->_vars["$tmp"]); }
        try{
            $this->_vars["$tmp"]["tableName"] = $table;
            $this->_vars["$tmp"]["dataToUpdate"] = $data;
            $this->_vars["$tmp"]["where"] = $where;

            ksort($this->_vars["$tmp"]["dataToUpdate"]);
            $fieldDetails = "";
            foreach ($this->_vars["$tmp"]["dataToUpdate"] as $key => $value) { $fieldDetails .= "`$key`=:$key,"; }
            $fieldDetails = rtrim($fieldDetails, ',');

            $this->_vars["$tmp"]["sqlQuery"] = "UPDATE `".$this->_vars["$tmp"]["tableName"]."` SET $fieldDetails WHERE ".$this->_vars["$tmp"]["where"];
        
            $sth = $this->_pdo->prepare($this->_vars["$tmp"]["sqlQuery"]);
            foreach ($this->_vars["$tmp"]["dataToUpdate"] as $key => $value) { $sth->bindValue(":$key", $value); }
            
            $this->_vars["$tmp"]["updateResults"] = $sth->execute();
        } catch (Exception $exc){
           // error/Exception handler
        }
        $re = $this->_vars["$tmp"]["updateResults"]; unset($this->_vars["$tmp"]);
        return $re;
    }

    /**
     * delete
     * 
     * @param string $table
     * @param string $where
     * @param integer $limit
     * @return integer the number of affected rows
     */
    public function delete($table, $where, $limit = 1) {
        $tmp = __FUNCTION__."_tmp"; if (isset($this->_vars["$tmp"])){ unset($this->_vars["$tmp"]); }
        try{
            $this->_vars["$tmp"]["tableName"] = $table;
            $this->_vars["$tmp"]["where"] = $where;
            $this->_vars["$tmp"]["limit"] = $limit;
            $this->_vars["$tmp"]["sqlQuery"] = "DELETE FROM `".$this->_vars["$tmp"]["tableName"]."` WHERE ".$this->_vars["$tmp"]["where"]." LIMIT ".$this->_vars["$tmp"]["limit"];
        
            $this->_vars["$tmp"]["deleteResults"] = $this->_pdo->exec($this->_vars["$tmp"]["sqlQuery"]);
        } catch (Exception $exc){
            // error/Exception handler
        }
        $re = $this->_vars["$tmp"]["deleteResults"]; unset($this->_vars["$tmp"]);
        return $re;
    }

    /**
     * delete_all
     * @param string $table
     * @param string $where
     * @return integer the number of affected rows
     */
    public function delete_all($table, $where) {
        $tmp = __FUNCTION__."_tmp"; if (isset($this->_vars["$tmp"])){ unset($this->_vars["$tmp"]); }
        try{
            $this->_vars["$tmp"]["tableName"] = $table;
            $this->_vars["$tmp"]["where"] = $where;
            $this->_vars["$tmp"]["sqlQuery"] = "DELETE FROM `".$this->_vars["$tmp"]["tableName"]."` WHERE ".$this->_vars["$tmp"]["where"];
        
            $this->_vars["$tmp"]["deleteAll_Results"] = $this->_pdo->exec($this->_vars["$tmp"]["sqlQuery"]);
        } catch (Exception $exc){
           // error/Exception handler
        }
        $re = $this->_vars["$tmp"]["deleteAll_Results"]; unset($this->_vars["$tmp"]);
        return $re;
    }

}